﻿import {observable, action, computed} from 'mobx'

const MaxDate = new Date(2050, 12, 31)

const MinDate = new Date(1900, 0, 1)
/**
 * 日历组件状态管理
 */
export class CalendarStore {
    constructor(value, minimum, maximum) {
        this.calendar = new Calendar(minimum, maximum)
        this.weeks = this.calendar.getWeeks()
        this.change(value, minimum, maximum)
    }

    @observable date
    @observable minimum
    @observable maximum
    @observable days
    @observable months
    @observable years
    @observable weeks
    @observable currentYear;
    @observable currentMonth;
    @observable currentDate;
    @observable yearCount = 20
    @observable format = ''

    @action
    change(value, minimum, maximum) {
        const date = Calendar.parseDate(value || new Date())
        this.minimum = minimum
        this.maximum = maximum
        this.currentYear = date.getFullYear()
        this.currentMonth = date.getMonth()
        this.currentDate = date.getDate()
        if (minimum) {
            this.calendar.minimum = minimum
        }
        if (maximum) {
            this.calendar.maximum = maximum
        }
    }

    @action
    renderYears() {
        this.years = this.calendar.getYears(this.yearCount, this.currentYear)
    }

    @action
    renderMonths() {
        this.months = this.calendar.getMonths(this.currentYear)
    }

    @action
    renderDays() {
        this.days = this.calendar.getCalendar(this.currentYear, this.currentMonth)
    }

    @action nextYear() {
        this.currentYear--
    }

    @action nextPageOfYear() {

    }

    @action prevYear() {
        this.currentYear--
    }

    @action
    nextMonth() {
        if (this.currentMonth === 12) {
            this.currentMonth = 1
            this.currentYear++
        } else {
            this.currentMonth++
        }
    }

    @action
    prevMonth() {
        if (this.currentMonth > 1) {
            this.currentMonth--
        } else {
            this.currentMonth = 12
            this.currentYear--
        }
    }

    @computed get canNextYear() {
    }

    @computed get canPrevYear() {
    }

    @computed get canPrevMonth() {

    }

    @computed get canNextMonth() {
    }


}

/**
 * 日历日期创建
 * 此
 */
export class Calendar {
    constructor(minimum, maxiumn) {
        if (minimum) {
            this.minimum = minimum
        }
        if (maxiumn) {
            this.maximum = maxiumn
        }
    }

    /**
     *
     * @param count
     * @param startYear
     * @returns {Array}
     */
    getYears(count = 20, startYear) {
        startYear = startYear || new Date().getFullYear()
        const left = Math.floor(count / 2)
        const years = []
        const addYear = (item) => {
            years.push({
                year: item,
                invalid: item > this.maximum.getFullYear() || item < this.minimum.getFullYear()
            })
        }
        for (let i = left; i > 0; i--) {
            addYear(startYear - i)
        }
        const right = Math.ceil(count / 2)
        for (let i = 0; i <= right; i++) {
            addYear(startYear + i)
        }
        return years
    }

    /**
     * 获取
     * @param year
     * @returns {Array}
     */
    getMonths(year) {
        let startMonth = 0, endMonth = 11
        if (year === this.minimum.getFullYear()) {
            startMonth = this.minimum.getMonth()
        } else if (year === this.maximum.getFullYear()) {
            endMonth = this.maximum.getMonth()
        }
        const months = []
        for (let m = 0; m <= 11; m++) {
            months.push({
                year: year,
                month: m + 1,
                invalid: m > startMonth && m < endMonth,
            })
        }
        return months
    }

    /**
     *
     * @param year  有效的年份
     * @param month 真实月份从1开始
     * @returns {Array}
     */
    getDays(year, month) {
        const daysInMonth = this.getDaysInMonth(year, month - 1)
        const days = []
        for (let i = 1; i <= daysInMonth; i++) {
            const date = new Date(year, month - 1, i)
            const item = {
                year,
                month,
                day: i,
                invalid: date < this.minimum || date > this.maximum
            }
            days.push(item)
        }
        return days
    }

    /**
     * 指定月份的天数
     * @param year
     * @param month  月份从1开始
     * @returns {number}
     */
    getDaysInMonth(year, month) {
        //这里月份是从1开始,下个月的第0天即本月的最后一天
        return new Date(year, month, 0).getDate()
    }

    /**
     *
     * @returns {string[]}
     */
    getWeeks() {
        return ['一', '二', '三', '四', '五', '六', '七']
    }

    /***
     * 创建日历数组
     * @param year 年份 完整年份
     * @param month 月份 从1开始
     * @param startWeek 起始周,默认是周一
     * @returns {Array} 指定年月和起始周日历数组
     */
    getCalendar(year, month, startWeek = 1) {
        const items = []
        const daysInMonth = this.getDaysInMonth(year, month) //获取本月天数
        const startDate = new Date(year, month - 1, 1)  //本月第一天
        const startDateInWeek = startDate.getDay()  //本月第一天是星期几,0表示星期天
        const addToDays = (year, month, day, invalid) => {
            const date = new Date(year, month, day)
            const item = {
                year,
                month: month + 1,
                day,
                invalid
            }
            if (!invalid) {
                if (date < this.minimum) {
                    item.invalid = true
                } else if (date > this.maximum) {
                    item.invalid = true
                }
            }
            items.push(item)
        }
        //非起始周,则补上个月日期
        if (startDateInWeek > startWeek) {
            const prevMonth = new Date(year, month - 1, -1 * (startDateInWeek - startWeek) + 1)
            const daysInPrevMonth = this.getDaysInMonth(prevMonth.getFullYear(), prevMonth.getMonth() + 1)
            //补上个月时间
            for (let day = prevMonth.getDate(); day <= daysInPrevMonth; day++) {
                addToDays(prevMonth.getFullYear(), prevMonth.getMonth(), day, true)
            }
        }
        //生成当前月
        for (let day = 1; day <= daysInMonth; day++) {
            addToDays(year, month - 1, day)
        }
        //获取下个月补位日期
        const nextMonth = new Date(year, month, 1)
        const nextMonthDays = 42 - items.length  //计算补位下个月天数
        for (let day = 1; day <= nextMonthDays; day++) {
            addToDays(nextMonth.getFullYear(), nextMonth.getMonth(), day, true)
        }
        return items
    }

    /**
     * 最大日期
     * @returns {*}
     */

    get maximum() {
        return this._maximum
    }

    set maximum(value) {
        this._maximum = Calendar.parseDate(value) || MaxDate
        return this._maximum
    }

    /**
     * 最小日期
     * @returns {*}
     */
    get minimum() {
        return this._minimum
    }

    set minimum(value) {
        this._minimum = Calendar.parseDate(value) || MinDate
        return this._minimum
    }


    static parseDate(value, safety) {
        if (!value) {
            throw new Error('无效的日期格式')
        }
        if (value instanceof Date) {
            return value
        } else if (typeof value === 'string') {
            //全部是数字按时间戳处理
            if (/^\d+$/.test(value)) {
                return new Date(parseInt(value,10) * 1000)
            }
            //仅适用于中国标准日期格式
            var parts = value.split(/[- /:]/g)
            if (parts.length > 1) {
                parts[1] = parseInt(parts[1],10) - 1
            }
            return new Date(...parts)
        } else if (typeof value === 'number') {
            return new Date(value * 1000)
        }
        throw new Error()
    }
}